---
title: "Aggregation - Custom Functions"
enterprise: true
---
This section covers how custom aggregation functions can be supplied and used in the grid.

{% gridExampleRunner title="Registering Functions" name="registering-functions" /%}

## Registering Custom Functions
Custom functions can be registered to the grid by name via the `aggFuncs` grid option. The functions can
then be applied to columns by referencing the function name in the column definition. The default values of
`"sum"`, `"min"`, `"max"`, `"first"`, `"last"`, `"count"` and `"avg"` can also be overwritten with custom
implementations.

The above example demonstrates the following configuration to register a custom `"range"` function and applies
it to the `total` column:
```{% frameworkTransform=true %}
const gridOptions = {
    columnDefs: [
        { field: 'total', aggFunc: 'range' },
    ],
    aggFuncs: {
        'range': params => {
            const values = params.values;
            return values.length > 0 ? Math.max(...values) - Math.min(...values) : null;
        }
    },
}
```

## Directly Applied Functions
For columns not [Configured via the UI](./aggregation-columns/#configuring-via-the-ui), it can be simpler to directly
apply custom functions to columns. This can be done by passing a custom function directly to the column `aggFunc`
property.

{% warning %}
Direct functions will not appear in the [Columns Tool Panel](./tool-panel-columns/), work when [Saving and Applying Column State](./column-state/#save-and-apply), or work with [Grid State](./grid-state/). To use these features, register custom functions instead.
{% /warning %}

{% gridExampleRunner title="Directly Applied Functions" name="applied-functions" /%}

The above example demonstrates the following configuration to apply a custom `"range"` function to the `total` column:
```{% frameworkTransform=true %}
const gridOptions = {
    columnDefs: [
        {
            field: 'total',
            aggFunc: params => {
                const values = params.values;
                return values.length > 0 ? Math.max(...values) - Math.min(...values) : null;
            }
        }
    ]
}
```

## Multiple Group Levels
When aggregations are applied across multiple levels of grouping, the aggregation function is called recursively.
This has the effect where some groups aggregate the results of other aggregations, causing incorrect results.

To handle this, the aggregation function should return an object containing relevant meta data for the next level of aggregation,
and a `"value"` field representing the result for this level.

{% gridExampleRunner title="Multiple Group Levels" name="multi-group-levels" /%}

The above example demonstrates the following configuration to apply a custom `"range"` function which works with multiple
levels of row grouping:
```{% frameworkTransform=true %}
const gridOptions = {
    columnDefs: [
      { field: 'total', aggFunc: 'range' },
      // ... other column definitions
    ],
    aggFuncs: {
      range: params => {
        const values = params.values;
        // aggregate leaf rows
        if (params.rowNode.leafGroup) {
            const max = Math.max(...values);
            const min = Math.min(...values);
            return {
                max: max,
                min: min,
                value: max - min,
            }
        }

        // aggregate group rows
        let max = values[0].max;
        let min = values[0].min;
        values.forEach(groupResult => {
            max = Math.max(max, groupResult.max);
            min = Math.min(min, groupResult.min);
        });
        return {
            max: max,
            min: min,
            value: max - min,
        };
      }
    },
}
```

## Next Up

Continue to the next section to learn about [Total Rows](./aggregation-total-rows/).
